package net.weamor.interfaces.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;

import net.weamor.interfaces.global.GlobalVar;
import net.weamor.interfaces.pojo.CertificateBean;
import net.weamor.interfaces.pojo.RequestParam;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;



/**
 * https 双向认证 工具类
 * @ClassName HttpsUtil  
 * @Description https 双向认证 工具类 
 *   
 */
public class HttpsKit {

	private static myHostnameVerifier1 hnv = new myHostnameVerifier1();
	private static final String KEY_STORE_TYPE_JKS = "jks";
	private static final String KEY_STORE_TYPE_P12 = "PKCS12";
	private static String KEY_STORE_CLIENT_PATH = "";
	private static String KEY_STORE_TRUST_PATH = "";
	//TODO 填写默认的密码
	private static String KEY_STORE_PASSWORD = "net.weamor";
	private static String KEY_STORE_TRUST_PASSWORD = "net.weamor";

	private static Logger logger = LoggerFactory.getLogger(HttpsKit.class);
	
	
	public static String httpsRequest(CertificateBean certificateBean,String url,
			Map<String, Object> formParams) throws Exception{
		StringBuffer respStr = new StringBuffer();
		CloseableHttpClient httpclient = HttpClients.createDefault();
		try {
			KeyStore keyStore = KeyStore.getInstance(certificateBean.getKeyStoreTypeP12());
			KeyStore trustStore = KeyStore.getInstance(certificateBean.getKeyStoreTypeJks());
			InputStream ksIn = new FileInputStream(certificateBean.getKeyStoreClientPath());
			InputStream tsIn = new FileInputStream(new File(
					certificateBean.getKeyStoreTrustPath()));
			try {
				keyStore.load(ksIn, certificateBean.getKeyStorePassword().toCharArray());
				trustStore.load(tsIn, certificateBean.getKeyStoreTrustPassword().toCharArray());
			} finally {
				try {
					ksIn.close();
					tsIn.close();
				} catch (Exception ignore) {
					ignore.printStackTrace();
				}
			}
			// 相信自己的CA和所有自签名的证书
			SSLContext sslcontext = SSLContexts
					.custom()
					.loadKeyMaterial(keyStore, certificateBean.getKeyStorePassword().toCharArray())
					.loadTrustMaterial(trustStore,
							new TrustSelfSignedStrategy()).build();

			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
					sslcontext, new String[] { "TLSv1" }, null, hnv);
			httpclient = HttpClients.custom().setSSLSocketFactory(sslsf)
					.build();

			//-----数据值处理-------
			HttpPost httpPost = new HttpPost(url);
			List<NameValuePair> nvps = new ArrayList<NameValuePair>();
			
			for(Map.Entry<String, Object> entry:formParams.entrySet()){    
			     nvps.add(new BasicNameValuePair(entry.getKey(), (String) entry.getValue()));
			}   
			
			httpPost.setEntity(new UrlEncodedFormEntity(nvps));
			//---------数据值处理end-----------
			
			logger.info("#I https双向请求的url为:"+url +" 参数:"+nvps.toString() +"  未base64前的param:"+formParams.toString());
			
			CloseableHttpResponse response2 = httpclient.execute(httpPost);
			try {
				HttpEntity entity2 = response2.getEntity();
				// 显示结果
				InputStream is = entity2.getContent();
				List<String> lines = IOUtils.readLines(is);
				for (int i = 0; i < lines.size(); i++) {
					respStr.append(lines.get(i));
				}
			} finally {
				response2.close();
			}
		} catch (Exception e) {
			logger.error("#E 调用https发生了异常 :"+e.getMessage());
		} finally {
			httpclient.close();
		}
		return respStr.toString();
	}
	
	/**
	 * @param SendStr	 发送字符串
	 * @return			 返回字符串
	 */
	public static String httpsRequest(CertificateBean certificateBean,RequestParam requestParam,
				String reqMethod)
			throws Exception {
		StringBuffer respStr = new StringBuffer();
		CloseableHttpClient httpclient = HttpClients.createDefault();
		try {
			KeyStore keyStore = KeyStore.getInstance(certificateBean.getKeyStoreTypeP12());
			KeyStore trustStore = KeyStore.getInstance(certificateBean.getKeyStoreTypeJks());
			InputStream ksIn = new FileInputStream(certificateBean.getKeyStoreClientPath());
			InputStream tsIn = new FileInputStream(new File(
					certificateBean.getKeyStoreTrustPath()));
			try {
				keyStore.load(ksIn, certificateBean.getKeyStorePassword().toCharArray());
				trustStore.load(tsIn, certificateBean.getKeyStoreTrustPassword().toCharArray());
			} finally {
				try {
					ksIn.close();
					tsIn.close();
				} catch (Exception ignore) {
					ignore.printStackTrace();
				}
			}
			// 相信自己的CA和所有自签名的证书
			SSLContext sslcontext = SSLContexts
					.custom()
					.loadKeyMaterial(keyStore, certificateBean.getKeyStorePassword().toCharArray())
					.loadTrustMaterial(trustStore,
							new TrustSelfSignedStrategy()).build();

			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
					sslcontext, new String[] { "TLSv1" }, null, hnv);
			httpclient = HttpClients.custom().setSSLSocketFactory(sslsf)
					.build();

			String url  = requestParam.getUrl();
			//-----数据值处理-------
			HttpPost httpPost = new HttpPost(url);
			List<NameValuePair> nvps = new ArrayList<NameValuePair>();

			String method = requestParam.getMethod();
			nvps.add(new BasicNameValuePair("pro", requestParam.getPro()));
			nvps.add(new BasicNameValuePair("method", method));
			nvps.add(new BasicNameValuePair("caller", requestParam.getCaller()));
			
			Object json = "";
			if ("string".equalsIgnoreCase(requestParam.getParamstyle())) {
				json = requestParam.getArgMap().get("param");
			} else if("map".equalsIgnoreCase(requestParam.getParamstyle())){
				json = requestParam.getArgMap();
			} else if("param".equalsIgnoreCase(requestParam.getParamstyle())){
				//这里是param类型，param类型要设置的参数位置为param
				json = requestParam.getParam();
			} else {
				throw new Exception("不能识别paramStyle，请指定参数类型为param|map|string");
			}
			
			//后期要根据参数来决定是否需要json
			json = GsonKit.toJson(json);
			
			//根据method选择不同的base64方法，当前安硕需要用原始的base64方法
			String base64Type = requestParam.getBase64Type();
			String base64 = "";
			if (StringUtils.isBlank(base64Type)) {
				base64 = Base64Kit.encodeString((String) json);
			} else if ("amarsoft".equals(base64Type)){
				base64 = EncrypyUtil.encryptBASE64(((String)json).getBytes(GlobalVar.DEFAULT_CHARSET));
			} 
			
			nvps.add(new BasicNameValuePair("param", base64));
			nvps.add(new BasicNameValuePair("paramstyle", requestParam.getParamstyle()));
			httpPost.setEntity(new UrlEncodedFormEntity(nvps));
			//---------数据值处理end-----------
			
			logger.info("#I https双向请求的url为:"+url +" 参数:"+nvps.toString() +"  未base64前的param:"+json);
			
			CloseableHttpResponse response2 = httpclient.execute(httpPost);
			try {
				HttpEntity entity2 = response2.getEntity();
				// 显示结果
				InputStream is = entity2.getContent();
				List<String> lines = IOUtils.readLines(is);
				for (int i = 0; i < lines.size(); i++) {
					respStr.append(lines.get(i));
				}
			} finally {
				response2.close();
			}
		} catch (Exception e) {
			logger.error("#E 调用https发生了异常 :"+e.getMessage());
		} finally {
			httpclient.close();
		}
		return respStr.toString();
	}
	
	/**
	 * @param SendStr	 发送字符串
	 * @return			 返回字符串
	 */
	public static String httpsRequest(String url,RequestParam req,String reqMethod)
			throws Exception {
		StringBuffer respStr = new StringBuffer();
		CloseableHttpClient httpclient = HttpClients.createDefault();
		try {
			KeyStore keyStore = KeyStore.getInstance(KEY_STORE_TYPE_P12);
			KeyStore trustStore = KeyStore.getInstance(KEY_STORE_TYPE_JKS);
			InputStream ksIn = new FileInputStream(KEY_STORE_CLIENT_PATH);
			InputStream tsIn = new FileInputStream(new File(
					KEY_STORE_TRUST_PATH));
			try {
				keyStore.load(ksIn, KEY_STORE_PASSWORD.toCharArray());
				trustStore.load(tsIn, KEY_STORE_TRUST_PASSWORD.toCharArray());
			} finally {
				try {
					ksIn.close();
				} catch (Exception ignore) {
				}
				try {
					tsIn.close();
				} catch (Exception ignore) {
				}
			}
			// 相信自己的CA和所有自签名的证书
			SSLContext sslcontext = SSLContexts
					.custom()
					.loadKeyMaterial(keyStore, KEY_STORE_PASSWORD.toCharArray())
					.loadTrustMaterial(trustStore,
							new TrustSelfSignedStrategy()).build();

			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
					sslcontext, new String[] { "TLSv1" }, null, hnv);
			httpclient = HttpClients.custom().setSSLSocketFactory(sslsf)
					.build();

			//-----数据值处理-------
			HttpPost httpPost = new HttpPost(url);
			List<NameValuePair> nvps = new ArrayList<NameValuePair>();

			String method = req.getMethod();
			nvps.add(new BasicNameValuePair("pro", req.getPro()));
			nvps.add(new BasicNameValuePair("method", method));
			nvps.add(new BasicNameValuePair("caller", req.getCaller()));
			
			Object json = "";
			
//			if ("json".equals(req.getParamstyle()) || "xml".equals(req.getParamstyle())) {
//				Param param = GsonKit.getJson(req.getJsonParams(), Param.class);
//				json = GsonKit.toJson(param.getValue());
//			} else {
//				if (req.getParam() != null) {
//					json =  GsonKit.toJson(req.getParam());
//				} else {
//					json = GsonKit.toJson(req.getParams());
//				}
//			}
//			
			String base64 = "";
			//根据method选择不同的base64方法，当前安硕需要用原始的base64方法
			if ("amrsoft".equals(method)) {
//				base64 =  EncrypyUtil.encryptBASE64(((String) json).getBytes("UTF-8"));
			} else {
				base64 = Base64Kit.encodeString((String) json);
			}
			
			nvps.add(new BasicNameValuePair("param", base64));
			nvps.add(new BasicNameValuePair("paramstyle", req.getParamstyle()));
			httpPost.setEntity(new UrlEncodedFormEntity(nvps));
			//---------数据值处理end-----------
			
			logger.info("#I https双向请求的url为:"+url +" 参数:"+nvps.toString() +"  未base64前的param:"+json);
			
			CloseableHttpResponse response2 = httpclient.execute(httpPost);
			try {
				HttpEntity entity2 = response2.getEntity();
				// 显示结果
				InputStream is = entity2.getContent();
				List<String> lines = IOUtils.readLines(is);
				for (int i = 0; i < lines.size(); i++) {
					respStr.append(lines.get(i));
				}
			} finally {
				response2.close();
			}
		} catch (Exception e) {
			logger.error("#E 调用https发生了异常 :"+e.getMessage());
		} finally {
			httpclient.close();
		}
		return respStr.toString();
	}
	
}

class myHostnameVerifier1 implements X509HostnameVerifier {

	public boolean verify(String hostname, SSLSession session) {
		System.out.println("Warning: URL Host: " + hostname + " vs. "
				+ session.getPeerHost());
		return true;
	}

	public void verify(String host, SSLSocket ssl) {
		return;
	}

	public void verify(String host, X509Certificate cert) {
		return;
	}

	public void verify(String host, String[] cns, String[] subjectAlts) {
		return;
	}

}
